package com.seocoo.worker.base;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;


public class LuBanFactory {
    LuBanFactory() {
    }

    static class Factors {
        public int height;
        public int width;
        public int inSampleSize;
        public int angle;
        public long minSize;
    }

    private static Factors evaluate(final File file) {
        if (!file.exists()) {
            throw new IllegalArgumentException("exception on checkFileExists");
        }
        String imagePath = file.getAbsolutePath();
        Factors factors = new Factors();
        factors.angle = getBitmapAngle(imagePath);

        final int[] dimen = getBitmapSize(imagePath);
        int tempW = dimen[0] % 2 == 1 ? dimen[0] + 1 : dimen[0];
        int tempH = dimen[1] % 2 == 1 ? dimen[1] + 1 : dimen[1];

        final int width = Math.min(tempH, tempW);
        final int height = Math.max(tempH, tempW);

        factors.width = width;
        factors.height = height;
        factors.inSampleSize = computeSize(width, height);
        return factors;
    }

    private static int computeSize(int srcWidth, int srcHeight) {
        srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
        srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;

        int longSide = Math.max(srcWidth, srcHeight);
        int shortSide = Math.min(srcWidth, srcHeight);

        float scale = ((float) shortSide / longSide);
        if (scale <= 1 && scale > 0.5625) {
            if (longSide < 1664) {
                return 1;
            } else if (longSide < 4990) {
                return 2;
            } else if (longSide > 4990 && longSide < 10240) {
                return 4;
            } else {
                return longSide / 1280 == 0 ? 1 : longSide / 1280;
            }
        } else if (scale <= 0.5625 && scale > 0.5) {
            return longSide / 1280 == 0 ? 1 : longSide / 1280;
        } else {
            return (int) Math.ceil(longSide / (1280.0 / scale));
        }
    }

    private static int[] getBitmapSize(String imagePath) {
        int[] size = new int[2];
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;
        BitmapFactory.decodeFile(imagePath, options);
        size[0] = options.outWidth;
        size[1] = options.outHeight;
        return size;
    }

    private static int getBitmapAngle(String imagePath) {
        int degree = 0;
        try {
            ExifInterface exif = new ExifInterface(imagePath);
            int value = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
            switch (value) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
        }
        return degree;
    }

    /***
     * 压缩图片文件
     *
     * @param inputFile
     * @return
     */
    public static File compress(File inputFile, File dstFile, long minSize) {

        if (inputFile == null || !inputFile.exists()) {
            throw new IllegalArgumentException("exception on checkFileExists");
        }

        boolean success = false;
        if (null != dstFile) {

            //step_1 压缩评估
            Factors factors = evaluate(inputFile);
            factors.minSize = minSize;
            //step_2 压缩输出
            success = output(inputFile, dstFile, factors);
        }
        return success ? dstFile : null;
    }

    // 压缩输出
    private static boolean output(File inputFile, final File outFile, Factors factors) {

        FileOutputStream fos = null;
        ByteArrayOutputStream stream = null;
        //旋转照片
        Bitmap bitmap = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = factors.inSampleSize;
            //比例压缩
            Bitmap bmp = BitmapFactory.decodeFile(inputFile.getAbsolutePath(), options);

            if (0 != factors.angle) {
                Matrix matrix = new Matrix();
                matrix.postRotate(factors.angle);
                bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
                bmp.recycle();
            } else {
                bitmap = bmp;
            }
            if (bitmap == null) {
                return false;
            }
            //质量压缩
            stream = new ByteArrayOutputStream();
            int quality = 100;

            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
            long length = stream.toByteArray().length / 1024;

            if (length > factors.minSize) {
                //二分估计最优质量值
                int left = 0, right = 0;

                long[] range = new long[]{factors.minSize - 5, factors.minSize + 10};
                do {
                    if (length < range[0]) {
                        left = quality;
                    } else if (length > range[1]) {
                        right = quality;
                    } else {
                        break;
                    }
                    quality = (right - left) / 2 + left;
                    stream.reset();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
                    length = stream.toByteArray().length / 1024;

                } while (quality > left && quality < right);
            }
            //输出文件
            fos = new FileOutputStream(outFile);
            fos.write(stream.toByteArray());
            fos.flush();

            return true;
        } catch (Exception e) {
        } finally {
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
            }
            try {
                if (stream != null) {
                    stream.close();
                }
            } catch (Exception e) {
            }
        }
        return false;
    }

}
